ReduceFusion
对输入张量沿指定轴(axes)做归约(Reduce)运算,将若干维度压缩为标量结果,得到更低维的输出张量。
支持一次指定多个归约轴:按 axes 顺序依次规约,前一次的中间结果作为后一次的输入。
设待规约轴长度为 \(N\) (即 axis_size),该轴上元素为 \(x_0, x_1, \ldots, x_{N-1}\),
则各 mode_ 对应计算如下:
- 计算过程:
由输入形状与
axes计算每个规约轴对应的outer_size、axis_size、inner_size。将输入按
outer × axis × inner展开;对每个(outer, inner)位置,沿axis维执行上述归约。若有多个规约轴,则重复步骤 2,中间结果写入
mid_buffer_0_/mid_buffer_1_乒乓缓冲,最后一轮写到输出。
- 输入:
src_data - 输入数据的地址
param - 算子计算所需参数的结构体。其各成员见下述。
core_mask - 核掩码(仅共享存储版本使用)。
ReduceParameter定义:
1typedef struct ReduceParameter {
2 void* tmp_src_data_; // 单核 _p 临时输入缓冲,需 total_num_ * sizeof(T) 字节
3 void* tmp_dst_data_; // 单核 _p 临时输出缓冲,需 output_num_ * sizeof(T) 字节
4 void* mid_buffer_0_; // 多轴规约中间结果缓冲 0
5 void* mid_buffer_1_; // 多轴规约中间结果缓冲 1
6 int* outer_sizes_; // 各规约轴 outer size,需 num_axes_ * sizeof(int) 字节
7 int* inner_sizes_; // 各规约轴 inner size,需 num_axes_ * sizeof(int) 字节
8 int* axis_sizes_; // 各规约轴 axis size,需 num_axes_ * sizeof(int) 字节
9 int total_num_; // 输入元素总数
10 int num_axes_; // 规约轴数量
11 int mode_; // 规约模式
12 int output_num_; // 输出元素数
13} ReduceParameter;
其中 T 为元素数据类型(如 fp32/int32 为 4 字节,fp16/int16 为 2 字节)。
缓冲分配说明:
tmp_src_data_/tmp_dst_data_:仅私有存储(_p)版本需要;共享存储(_s)可不设置。
mid_buffer_0_/mid_buffer_1_:各需outer_sizes_[0] * inner_sizes_[0] * sizeof(T)字节。
num_axes_ <= 1:两块均不使用
num_axes_ == 2:仅使用mid_buffer_0_
num_axes_ >= 3:两块均需分配(乒乓复用)
outer_sizes_/inner_sizes_/axis_sizes_:各需num_axes_个int。若将
tmp_src_data_/tmp_dst_data_/mid_buffer_*放在本核 AM,须避开算子硬编码工作区[0x10000000, 0x10020400),否则会被分块矩阵搬移覆盖。
其中 mode_ 的取值与规约方法的对应关系如下:
ReduceMean = 0
ReduceMax = 1
ReduceMin = 2
ReduceProd = 3
ReduceSum = 4
ReduceSumSquare = 5
ReduceASum = 6
ReduceL2Norm = 7
- 输出:
dst_data - 输出地址。
- 支持平台:
FT78NEMT7004
备注
FT78NE 支持 int8, int16, int32, fp32, fp64
MT7004 支持 fp16, fp32, int16, int32
共享存储版本:
-
void i8_reduce_s(int8_t *src_data, int8_t *dst_data, ReduceParameter *param, int core_mask)
-
void i16_reduce_s(short *src_data, short *dst_data, ReduceParameter *param, int core_mask)
-
void i32_reduce_s(int *src_data, int *dst_data, ReduceParameter *param, int core_mask)
-
void hp_reduce_s(float16 *src_data, float16 *dst_data, ReduceParameter *param, int core_mask)
-
void fp_reduce_s(float *src_data, float *dst_data, ReduceParameter *param, int core_mask)
-
void dp_reduce_s(double *src_data, double *dst_data, ReduceParameter *param, int core_mask)
C调用示例:
1// MT7004 示例(共享存储多核,DDR 地址)
2void Resize(ReduceParameter* param, int ndim, int* input_shape, int num_axes, int* axes) {
3 int tmp_input_shape[8];
4 int total_num = 1;
5 int i, j, k;
6 for (i = 0; i < ndim; i++) {
7 tmp_input_shape[i] = input_shape[i];
8 total_num *= input_shape[i];
9 }
10 param->total_num_ = total_num;
11 int offset_size = 0;
12 for (i = 0; i < num_axes; ++i) {
13 int axis = axes[i];
14 int outer_size = 1;
15 for (j = 0; j < axis; j++) {
16 outer_size *= tmp_input_shape[j];
17 }
18 param->outer_sizes_[offset_size] = outer_size;
19 int inner_size = 1;
20 for (k = axis + 1; k < ndim; k++) {
21 inner_size *= tmp_input_shape[k];
22 }
23 param->inner_sizes_[offset_size] = inner_size;
24 param->axis_sizes_[offset_size] = tmp_input_shape[axis];
25 offset_size++;
26 tmp_input_shape[axis] = 1;
27 }
28 if (num_axes == 0) {
29 param->output_num_ = total_num;
30 } else {
31 param->output_num_ = param->outer_sizes_[num_axes - 1] * param->inner_sizes_[num_axes - 1];
32 }
33}
34
35void TestReduceSMCFp32(int* input_shape, int ndim, int* axes, int num_axes, int mode, int core_mask) {
36 int core_id = get_core_id();
37 int logic_core_id = GetLogicCoreId(core_mask, core_id);
38 int core_num = GetCoreNum(core_mask);
39 float* input = (float*)0x88000000;
40 float* output = (float*)0x98000000;
41 ReduceParameter* param = (ReduceParameter*)0xA8480000;
42 if (logic_core_id == 0) {
43 param->num_axes_ = num_axes;
44 param->mode_ = mode;
45 param->inner_sizes_ = (int*)0xA8484000;
46 param->outer_sizes_ = (int*)0xA8485000;
47 param->axis_sizes_ = (int*)0xA8486000;
48 param->mid_buffer_0_ = (void*)0xA9490000;
49 param->mid_buffer_1_ = (void*)0xAA490000;
50 Resize(param, ndim, input_shape, num_axes, axes);
51 }
52 sys_bar(0, core_num); // 初始化参数完成后进行同步
53 fp_reduce_s(input, output, param, core_mask);
54}
55
56void main(){
57 int input_shape[3] = {4, 5, 5};
58 int ndim = 3;
59 int axes[1] = {1};
60 int num_axes = 1;
61 int mode = 0; // ReduceMean
62 int core_mask = 0b1111;
63 TestReduceSMCFp32(input_shape, ndim, axes, num_axes, mode, core_mask);
64}
私有存储版本:
-
void i8_reduce_p(int8_t *src_data, int8_t *dst_data, ReduceParameter *param)
-
void i16_reduce_p(short *src_data, short *dst_data, ReduceParameter *param)
-
void i32_reduce_p(int *src_data, int *dst_data, ReduceParameter *param)
-
void hp_reduce_p(float16 *src_data, float16 *dst_data, ReduceParameter *param)
-
void fp_reduce_p(float *src_data, float *dst_data, ReduceParameter *param)
-
void dp_reduce_p(double *src_data, double *dst_data, ReduceParameter *param)
C调用示例:
1// MT7004 示例(私有存储单核,AM 地址)
2// tmp/mid 缓冲须避开 [0x10000000, 0x10020400)
3void TestReduceAMFp32(int* input_shape, int ndim, int* axes, int num_axes, int mode) {
4 float* input = (float*)0x10000000;
5 float* output = (float*)0x10010000;
6 float* tmp_src = (float*)0x10028000;
7 float* tmp_dst = (float*)0x10038000;
8 ReduceParameter* param = (ReduceParameter*)0x10048000;
9 param->num_axes_ = num_axes;
10 param->mode_ = mode;
11 param->inner_sizes_ = (int*)0x10049000;
12 param->outer_sizes_ = (int*)0x1004A000;
13 param->axis_sizes_ = (int*)0x1004B000;
14 param->mid_buffer_0_ = (void*)0x10050000;
15 param->mid_buffer_1_ = (void*)0x10060000;
16 param->tmp_src_data_ = tmp_src;
17 param->tmp_dst_data_ = tmp_dst;
18 Resize(param, ndim, input_shape, num_axes, axes);
19
20 fp_reduce_p(input, output, param);
21}
22
23void main() {
24 int input_shape[3] = {4, 5, 5};
25 int ndim = 3;
26 int axes[1] = {1};
27 int num_axes = 1;
28 int mode = 0; // ReduceMean
29 TestReduceAMFp32(input_shape, ndim, axes, num_axes, mode);
30}